Skip to content

[ECO-5429] Message reactions tests#332

Merged
maratal merged 3 commits intomainfrom
304-message-reactions-tests
Aug 15, 2025
Merged

[ECO-5429] Message reactions tests#332
maratal merged 3 commits intomainfrom
304-message-reactions-tests

Conversation

@maratal
Copy link
Copy Markdown
Collaborator

@maratal maratal commented Jul 19, 2025

Closes #304

Summary by CodeRabbit

  • Refactor

    • Streamlined internal handling of default reaction options and improved error handling for raw message reactions.
    • Simplified logic for reaction name assignment in raw reaction subscriptions.
    • Updated error reporting to use standardized chat error codes for message sending and updating.
    • Enhanced parsing flexibility for specification coverage by allowing leading whitespace in spec point lines.
  • Tests

    • Added extensive tests for sending, deleting, and subscribing to message reactions, including error handling and configuration scenarios.
    • Improved coverage for reaction summary and raw event subscriptions, ensuring robust validation of reaction behaviors.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jul 19, 2025

Walkthrough

The changes introduce comprehensive asynchronous unit tests for the DefaultMessageReactions feature, refactor internal properties and error handling in the implementation, and update a comment in the API to reference the correct error code. No public API signatures are modified; all updates are internal or in test coverage.

Changes

File(s) Change Summary
Chat API error handling update
Sources/AblyChat/ChatAPI.swift
Changed error throwing in sendMessage and updateMessage to use predefined .clientIdRequired error; updated comment reference for invalid message serial error in sendReactionToMessage.
DefaultMessageReactions internal refactor
Sources/AblyChat/DefaultMessageReactions.swift
Replaced defaultReaction property with options; added guard clause for raw message reactions subscription; simplified reaction name handling and removed special-case logging.
Extensive async tests for message reactions
Tests/AblyChatTests/DefaultMessageReactionsTests.swift
Added multiple async unit tests covering sending, deleting, subscribing, error handling, raw event processing, and configuration of message reactions.
Build tool regex adjustment
Sources/BuildTool/BuildTool.swift
Modified regex to allow optional leading whitespace before asterisks in spec point line parsing.

Sequence Diagram(s)

sequenceDiagram
    participant TestSuite
    participant DefaultMessageReactions
    participant MockHTTP
    participant MockChannel

    TestSuite->>DefaultMessageReactions: sendReactionToMessage()
    DefaultMessageReactions->>MockHTTP: POST /send-reaction
    MockHTTP-->>DefaultMessageReactions: HTTP Response
    DefaultMessageReactions-->>TestSuite: Result/Error

    TestSuite->>DefaultMessageReactions: deleteReactionFromMessage()
    DefaultMessageReactions->>MockHTTP: DELETE /delete-reaction
    MockHTTP-->>DefaultMessageReactions: HTTP Response
    DefaultMessageReactions-->>TestSuite: Result/Error

    TestSuite->>DefaultMessageReactions: subscribeToReactionSummaries()
    DefaultMessageReactions->>MockChannel: Subscribe to summary events
    MockChannel-->>DefaultMessageReactions: Event Data
    DefaultMessageReactions-->>TestSuite: Parsed Event

    TestSuite->>DefaultMessageReactions: subscribeRaw()
    DefaultMessageReactions->>MockChannel: Subscribe to raw events
    MockChannel-->>DefaultMessageReactions: Raw Event Data
    DefaultMessageReactions-->>TestSuite: Parsed Event/Error
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Assessment against linked issues

Objective Addressed Explanation
Add tests for message reactions (#304, ECO-5429)

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
Regex change in Sources/BuildTool/BuildTool.swift This change relates to spec parsing in the build tool and is unrelated to message reactions or tests.

Poem

🐇 In code’s quiet glen, reactions arise,
Tested with care beneath watchful eyes.
Errors refined, defaults set just right,
Async tests dance in the soft moonlight.
With hops and with joy, this rabbit proclaims:
“Our chat now robust, in reaction’s bright flames!” 🌟

Note

🔌 MCP (Model Context Protocol) integration is now available in Early Access!

Pro users can now connect to remote MCP servers under the Integrations page to get reviews and chat conversations that understand additional development context.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 304-message-reactions-tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@maratal maratal changed the base branch from main to 301-all-errors-via-ChatError July 19, 2025 00:11
@github-actions github-actions Bot temporarily deployed to staging/pull/332/AblyChat July 19, 2025 00:12 Inactive
@maratal maratal force-pushed the 304-message-reactions-tests branch from 39a6c94 to f078af2 Compare July 19, 2025 00:23
@github-actions github-actions Bot temporarily deployed to staging/pull/332/AblyChat July 19, 2025 00:24 Inactive
@maratal maratal force-pushed the 304-message-reactions-tests branch from f078af2 to 9b72e35 Compare July 19, 2025 00:37
@github-actions github-actions Bot temporarily deployed to staging/pull/332/AblyChat July 19, 2025 00:38 Inactive
@maratal maratal force-pushed the 304-message-reactions-tests branch from 9b72e35 to 82bfaf3 Compare July 19, 2025 01:00
@github-actions github-actions Bot temporarily deployed to staging/pull/332/AblyChat July 19, 2025 01:01 Inactive
@maratal maratal force-pushed the 304-message-reactions-tests branch from 82bfaf3 to 3a63c26 Compare July 19, 2025 01:09
@github-actions github-actions Bot temporarily deployed to staging/pull/332/AblyChat July 19, 2025 01:11 Inactive
@maratal maratal force-pushed the 304-message-reactions-tests branch from 3a63c26 to 52c3dd2 Compare July 19, 2025 01:17
@github-actions github-actions Bot temporarily deployed to staging/pull/332/AblyChat July 19, 2025 01:18 Inactive
@maratal maratal force-pushed the 304-message-reactions-tests branch from 52c3dd2 to 987931e Compare July 19, 2025 01:24
@github-actions github-actions Bot temporarily deployed to staging/pull/332/AblyChat July 19, 2025 01:26 Inactive
@maratal maratal force-pushed the 304-message-reactions-tests branch from 987931e to 15a9d60 Compare July 19, 2025 01:31
@github-actions github-actions Bot temporarily deployed to staging/pull/332/AblyChat July 19, 2025 01:32 Inactive
@maratal
Copy link
Copy Markdown
Collaborator Author

maratal commented Jul 19, 2025

Coverage fails with:

Error: conformanceToNonexistentSpecPoints(specPointIDs: ["CHA-MR3b", "CHA-MR3b2", "CHA-MR3b3", "CHA-MR6a", "CHA-MR6a3", "CHA-MR7b", "CHA-MR7b1", "CHA-MR7b3"])

But those spec points exist in the main branch:
https://sdk.ably.com/builds/ably/specification/main/chat-features

What might be wrong here? @AndyTWF @lawrence-forooghian

@maratal maratal force-pushed the 304-message-reactions-tests branch from 15a9d60 to 57ba666 Compare July 19, 2025 11:39
@github-actions github-actions Bot temporarily deployed to staging/pull/332/AblyChat July 19, 2025 11:41 Inactive
@maratal maratal force-pushed the 304-message-reactions-tests branch from 57ba666 to e737a23 Compare July 19, 2025 11:49
@github-actions github-actions Bot temporarily deployed to staging/pull/332/AblyChat July 19, 2025 11:50 Inactive
@maratal maratal marked this pull request as ready for review July 19, 2025 12:11
@maratal maratal changed the title Message reactions tests [ECO-5429] Message reactions tests Jul 19, 2025
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2065a8a and e737a23.

📒 Files selected for processing (3)
  • Sources/AblyChat/ChatAPI.swift (1 hunks)
  • Sources/AblyChat/DefaultMessageReactions.swift (5 hunks)
  • Tests/AblyChatTests/DefaultMessageReactionsTests.swift (4 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Sources/AblyChat/Message.swift:163-175
Timestamp: 2025-06-14T21:58:57.802Z
Learning: In the AblyChat Swift SDK, the JSON key "reactions" is used for parsing reaction summaries in the Chat SDK layer, while "summary" is used in the ably-cocoa layer. Reactions can be sourced from either the realtime message's summary property or directly from the "reactions" dictionary in the JSON.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Example/AblyChatExample/MessageViews/MessageReactionsSheet.swift:15-31
Timestamp: 2025-06-14T16:18:47.038Z
Learning: In the AblyChat Swift SDK, there are three message reaction types: unique (one reaction per client per message), distinct (one reaction of each type per client per message), and multiple (any number of reactions including repeats, with counts). The MessageReactionsSheet specifically handles unique/distinct reactions where the count is always 1 per client per emoji. Only the "multiple" reaction type would have accumulating counts.
Learnt from: maratal
PR: ably/ably-chat-swift#165
File: Sources/AblyChat/Reaction.swift:14-14
Timestamp: 2024-12-10T01:59:02.065Z
Learning: For the 'ably-chat-swift' repository, documentation-only PRs should focus exclusively on public methods and properties. Avoid suggesting changes to internal comments or private methods in such PRs.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:29:39.712Z
Learning: The ably-chat-swift project uses Swift Testing framework (`#expect` macros) rather than XCTest for test assertions.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:29:39.712Z
Learning: The ably-chat-swift project uses Swift Testing framework (`#expect` macros) rather than XCTest for test assertions.
Learnt from: maratal
PR: ably/ably-chat-swift#249
File: Tests/AblyChatTests/DefaultMessagesTests.swift:45-48
Timestamp: 2025-05-22T19:17:21.392Z
Learning: The `let doIt = {}` closures in DefaultMessagesTests.swift are temporary workarounds for compiler crashes (related to issue #233) and will be removed once Xcode 16.3 is released, so they should not be flagged for missing async/throws annotations.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Tests/AblyChatTests/Mocks/MockRealtime.swift:41-47
Timestamp: 2025-06-14T15:18:17.427Z
Learning: In the MockRealtime class in Tests/AblyChatTests/Mocks/MockRealtime.swift, the body parameter in the request method is constrained to dictionary or array types, but currently only dictionary types are used. Arrays are not yet used for this method, so the current implementation assumes dictionary-only for simplicity.
Sources/AblyChat/ChatAPI.swift (8)
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Sources/AblyChat/Message.swift:163-175
Timestamp: 2025-06-14T21:58:57.802Z
Learning: In the AblyChat Swift SDK, the JSON key "reactions" is used for parsing reaction summaries in the Chat SDK layer, while "summary" is used in the ably-cocoa layer. Reactions can be sourced from either the realtime message's summary property or directly from the "reactions" dictionary in the JSON.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Example/AblyChatExample/MessageViews/MessageReactionsSheet.swift:15-31
Timestamp: 2025-06-14T16:18:47.038Z
Learning: In the AblyChat Swift SDK, there are three message reaction types: unique (one reaction per client per message), distinct (one reaction of each type per client per message), and multiple (any number of reactions including repeats, with counts). The MessageReactionsSheet specifically handles unique/distinct reactions where the count is always 1 per client per emoji. Only the "multiple" reaction type would have accumulating counts.
Learnt from: maratal
PR: ably/ably-chat-swift#165
File: Sources/AblyChat/Reaction.swift:14-14
Timestamp: 2024-12-10T01:59:02.065Z
Learning: For the 'ably-chat-swift' repository, documentation-only PRs should focus exclusively on public methods and properties. Avoid suggesting changes to internal comments or private methods in such PRs.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/SubscriptionAsyncSequence.swift:36-41
Timestamp: 2025-06-29T16:02:43.988Z
Learning: In the AblyChat Swift codebase, the fatalError in SubscriptionAsyncSequence.swift's mock async sequence handling (around line 39) is intentional and should not be flagged. This fatalError catches programmer errors when a throwing AsyncSequence is incorrectly passed to the mock initializer, which is meant for testing/development purposes.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Tests/AblyChatTests/Mocks/MockRealtime.swift:41-47
Timestamp: 2025-06-14T15:18:17.427Z
Learning: In the MockRealtime class in Tests/AblyChatTests/Mocks/MockRealtime.swift, the body parameter in the request method is constrained to dictionary or array types, but currently only dictionary types are used. Arrays are not yet used for this method, so the current implementation assumes dictionary-only for simplicity.
Learnt from: maratal
PR: ably/ably-chat-swift#249
File: Tests/AblyChatTests/DefaultMessagesTests.swift:45-48
Timestamp: 2025-05-22T19:17:21.392Z
Learning: The `let doIt = {}` closures in DefaultMessagesTests.swift are temporary workarounds for compiler crashes (related to issue #233) and will be removed once Xcode 16.3 is released, so they should not be flagged for missing async/throws annotations.
Learnt from: maratal
PR: ably/ably-chat-swift#165
File: docs-coverage-report:5-8
Timestamp: 2024-12-10T01:59:12.404Z
Learning: In the AblyChat Swift project, documentation coverage should focus on public methods and properties. Private and internal entities do not require documentation.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Example/AblyChatExample/ContentView.swift:94-99
Timestamp: 2025-06-14T21:47:20.509Z
Learning: In the Ably Chat Swift example app, using fatalError for missing clientID is intentional and appropriate since it represents a programmer error rather than a recoverable runtime condition. The clientID is considered an essential configuration requirement.
Sources/AblyChat/DefaultMessageReactions.swift (17)
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Example/AblyChatExample/MessageViews/MessageReactionsSheet.swift:15-31
Timestamp: 2025-06-14T16:18:47.038Z
Learning: In the AblyChat Swift SDK, there are three message reaction types: unique (one reaction per client per message), distinct (one reaction of each type per client per message), and multiple (any number of reactions including repeats, with counts). The MessageReactionsSheet specifically handles unique/distinct reactions where the count is always 1 per client per emoji. Only the "multiple" reaction type would have accumulating counts.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Sources/AblyChat/Message.swift:163-175
Timestamp: 2025-06-14T21:58:57.802Z
Learning: In the AblyChat Swift SDK, the JSON key "reactions" is used for parsing reaction summaries in the Chat SDK layer, while "summary" is used in the ably-cocoa layer. Reactions can be sourced from either the realtime message's summary property or directly from the "reactions" dictionary in the JSON.
Learnt from: maratal
PR: ably/ably-chat-swift#249
File: Tests/AblyChatTests/DefaultMessagesTests.swift:45-48
Timestamp: 2025-05-22T19:17:21.392Z
Learning: The `let doIt = {}` closures in DefaultMessagesTests.swift are temporary workarounds for compiler crashes (related to issue #233) and will be removed once Xcode 16.3 is released, so they should not be flagged for missing async/throws annotations.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/DefaultOccupancy.swift:10-13
Timestamp: 2025-05-12T21:01:14.109Z
Learning: The `Occupancy` protocol in the Ably Chat Swift SDK is annotated with `@MainActor`, making all conforming types like `DefaultOccupancy` automatically main actor-isolated without requiring explicit annotations on their methods.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/DefaultTyping.swift:11-14
Timestamp: 2025-05-12T21:03:31.914Z
Learning: The `Typing` protocol in the Ably Chat Swift SDK is annotated with `@MainActor`, making all conforming types like `DefaultTyping` automatically main actor-isolated without requiring explicit annotations on their methods.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/DefaultTyping.swift:11-14
Timestamp: 2025-05-12T21:03:31.914Z
Learning: The `Typing` protocol in the Ably Chat Swift SDK is annotated with `@MainActor`, making all conforming types like `DefaultTyping` automatically main actor-isolated without requiring explicit annotations on their methods.
Learnt from: maratal
PR: ably/ably-chat-swift#165
File: Sources/AblyChat/Reaction.swift:14-14
Timestamp: 2024-12-10T01:59:02.065Z
Learning: For the 'ably-chat-swift' repository, documentation-only PRs should focus exclusively on public methods and properties. Avoid suggesting changes to internal comments or private methods in such PRs.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/DefaultTyping.swift:131-138
Timestamp: 2025-05-12T21:04:36.263Z
Learning: In the AblyChat Swift codebase, SubscriptionHandle closures should capture self weakly with `[weak self]` to avoid potential retain cycles, particularly when calling channel.unsubscribe() within the closure.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/SubscriptionAsyncSequence.swift:36-41
Timestamp: 2025-06-29T16:02:43.988Z
Learning: In the AblyChat Swift codebase, the fatalError in SubscriptionAsyncSequence.swift's mock async sequence handling (around line 39) is intentional and should not be flagged. This fatalError catches programmer errors when a throwing AsyncSequence is incorrectly passed to the mock initializer, which is meant for testing/development purposes.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/RoomReactions.swift:42-56
Timestamp: 2025-05-16T21:35:46.634Z
Learning: In the AblyChat framework, all subscription callbacks are annotated with @MainActor, ensuring they always execute on the main actor thread without requiring additional Task wrappers.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:29:39.712Z
Learning: In the ably-chat-swift project, MockRealtimeChannel processes messages synchronously when subscribe is called, immediately delivering the configured messages to the callback.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:29:39.712Z
Learning: In the ably-chat-swift project, MockRealtimeChannel processes messages synchronously when subscribe is called, immediately delivering the configured messages to the callback.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/SubscriptionHandleStorage.swift:37-40
Timestamp: 2025-05-12T21:02:28.274Z
Learning: In the AblyChat Swift codebase, the `SubscriptionHandle` struct has an `unsubscribe()` method for terminating subscriptions, not a `cancel()` method.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/RoomLifecycleManager.swift:611-624
Timestamp: 2025-05-22T20:57:48.147Z
Learning: In AblyChat Swift, when using continuations with subscription callbacks, the continuation object is captured directly by the closure and doesn't depend on `self`. Even with `[weak self]` capture, the continuation will still be resumed properly.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Example/AblyChatExample/ContentView.swift:203-209
Timestamp: 2025-05-12T21:11:08.937Z
Learning: In the AblyChat Swift codebase, SubscriptionHandle doesn't need to be retained/stored to keep subscriptions active. The subscription callbacks continue to work even when the handle is not stored, as the underlying services maintain their own storage of callbacks that remain registered until explicitly unsubscribed via the handle's unsubscribe() method.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Example/AblyChatExample/ContentView.swift:203-209
Timestamp: 2025-05-12T21:11:08.937Z
Learning: In the AblyChat Swift codebase, SubscriptionHandle doesn't need to be retained/stored to keep subscriptions active. The subscription continues to work even if the handle is not stored, as the underlying services maintain references to the callbacks until explicitly unsubscribed via the handle's unsubscribe() method.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:20:38.904Z
Learning: In Swift tests using mock objects like MockRealtimeChannel, explicit subscription cleanup (via unsubscribe() or similar methods) is generally unnecessary since the mocks don't maintain real connections and will be garbage collected after the test completes.
Tests/AblyChatTests/DefaultMessageReactionsTests.swift (14)
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Example/AblyChatExample/MessageViews/MessageReactionsSheet.swift:15-31
Timestamp: 2025-06-14T16:18:47.038Z
Learning: In the AblyChat Swift SDK, there are three message reaction types: unique (one reaction per client per message), distinct (one reaction of each type per client per message), and multiple (any number of reactions including repeats, with counts). The MessageReactionsSheet specifically handles unique/distinct reactions where the count is always 1 per client per emoji. Only the "multiple" reaction type would have accumulating counts.
Learnt from: maratal
PR: ably/ably-chat-swift#249
File: Tests/AblyChatTests/DefaultMessagesTests.swift:45-48
Timestamp: 2025-05-22T19:17:21.392Z
Learning: The `let doIt = {}` closures in DefaultMessagesTests.swift are temporary workarounds for compiler crashes (related to issue #233) and will be removed once Xcode 16.3 is released, so they should not be flagged for missing async/throws annotations.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Sources/AblyChat/Message.swift:163-175
Timestamp: 2025-06-14T21:58:57.802Z
Learning: In the AblyChat Swift SDK, the JSON key "reactions" is used for parsing reaction summaries in the Chat SDK layer, while "summary" is used in the ably-cocoa layer. Reactions can be sourced from either the realtime message's summary property or directly from the "reactions" dictionary in the JSON.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Example/AblyChatExample/Mocks/MockRealtime.swift:348-384
Timestamp: 2025-06-14T16:19:29.327Z
Learning: The MockRealtime class in Example/AblyChatExample/Mocks/MockRealtime.swift is specifically for example app construction, not for testing. The actual test mocks are located in the Tests directory. If example app mocks are unused, fatalError calls are appropriate to catch accidental usage.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Tests/AblyChatTests/Mocks/MockRealtime.swift:41-47
Timestamp: 2025-06-14T15:18:17.427Z
Learning: In the MockRealtime class in Tests/AblyChatTests/Mocks/MockRealtime.swift, the body parameter in the request method is constrained to dictionary or array types, but currently only dictionary types are used. Arrays are not yet used for this method, so the current implementation assumes dictionary-only for simplicity.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:29:39.712Z
Learning: The ably-chat-swift project uses Swift Testing framework (`#expect` macros) rather than XCTest for test assertions.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:29:39.712Z
Learning: The ably-chat-swift project uses Swift Testing framework (`#expect` macros) rather than XCTest for test assertions.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/DefaultTyping.swift:11-14
Timestamp: 2025-05-12T21:03:31.914Z
Learning: The `Typing` protocol in the Ably Chat Swift SDK is annotated with `@MainActor`, making all conforming types like `DefaultTyping` automatically main actor-isolated without requiring explicit annotations on their methods.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/DefaultTyping.swift:11-14
Timestamp: 2025-05-12T21:03:31.914Z
Learning: The `Typing` protocol in the Ably Chat Swift SDK is annotated with `@MainActor`, making all conforming types like `DefaultTyping` automatically main actor-isolated without requiring explicit annotations on their methods.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/SubscriptionAsyncSequence.swift:36-41
Timestamp: 2025-06-29T16:02:43.988Z
Learning: In the AblyChat Swift codebase, the fatalError in SubscriptionAsyncSequence.swift's mock async sequence handling (around line 39) is intentional and should not be flagged. This fatalError catches programmer errors when a throwing AsyncSequence is incorrectly passed to the mock initializer, which is meant for testing/development purposes.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:29:39.712Z
Learning: In the ably-chat-swift project, MockRealtimeChannel processes messages synchronously when subscribe is called, immediately delivering the configured messages to the callback.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:29:39.712Z
Learning: In the ably-chat-swift project, MockRealtimeChannel processes messages synchronously when subscribe is called, immediately delivering the configured messages to the callback.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:20:38.904Z
Learning: In Swift tests using mock objects like MockRealtimeChannel, explicit subscription cleanup (via unsubscribe() or similar methods) is generally unnecessary since the mocks don't maintain real connections and will be garbage collected after the test completes.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Example/AblyChatExample/Mocks/MockClients.swift:0-0
Timestamp: 2025-05-16T21:04:26.244Z
Learning: In the ably-chat-swift project, mock implementations (like those in MockClients.swift) are intentionally kept simple, sometimes omitting parameter-based filtering behavior for testing simplicity.
🧬 Code Graph Analysis (1)
Tests/AblyChatTests/DefaultMessageReactionsTests.swift (5)
Sources/AblyChat/ChatAPI.swift (1)
  • sendReactionToMessage (201-216)
Sources/AblyChat/DefaultMessageReactions.swift (4)
  • send (22-40)
  • delete (43-59)
  • subscribe (62-97)
  • subscribeRaw (100-143)
Example/AblyChatExample/Mocks/MockClients.swift (13)
  • send (158-173)
  • send (245-262)
  • send (318-329)
  • delete (192-207)
  • delete (264-274)
  • subscribe (125-152)
  • subscribe (276-300)
  • subscribe (331-348)
  • subscribe (362-378)
  • subscribe (530-532)
  • subscribe (534-536)
  • subscribe (550-561)
  • subscribeRaw (302-304)
Tests/AblyChatTests/Helpers/Helpers.swift (1)
  • hasRecord (152-163)
Tests/AblyChatTests/Mocks/MockRealtimeChannel.swift (2)
  • subscribe (140-142)
  • subscribe (145-151)
🔇 Additional comments (8)
Sources/AblyChat/ChatAPI.swift (1)

202-202: Documentation fix looks correct.

The spec reference has been properly updated from "(CHA-MR11a1)" to "(CHA-MR4a1)" to match the send reaction method context. This aligns with the specification structure where CHA-MR4 covers sending reactions and CHA-MR11 covers deleting reactions.

Sources/AblyChat/DefaultMessageReactions.swift (3)

10-10: Clean refactoring to use MessagesOptions.

The change from storing defaultReaction to storing the full options object is a good improvement. It provides better encapsulation and allows access to other message-related configuration in the future without additional refactoring.

Also applies to: 18-18, 30-30, 44-44


103-107: Intentional breaking change: fatalError instead of throwing.

The change from throwing an error to using fatalError is a breaking API change. However, the comment clearly explains this is intentional because calling subscribeRaw without proper configuration is a programmer error that should be caught during development, not a runtime condition.

This aligns with the established pattern in the codebase for handling programmer errors.


128-128: Simplified reaction name handling.

Good simplification - removing the special case logic for delete operations and always using the fallback to empty string aligns with the CHA-MR7b3 specification requirements for default values.

Tests/AblyChatTests/DefaultMessageReactionsTests.swift (4)

7-60: Excellent test coverage for message reactions.

The test comprehensively covers both sending and deleting reactions with proper verification of HTTP request parameters. The spec references are well documented.


114-168: Well-structured subscription test with comprehensive type validation.

Great test coverage for reaction summaries including proper type checking and validation of all three reaction types (unique, distinct, multiple). The synchronous callback verification ensures the mock behavior is working as expected.


203-246: Good validation of raw reaction subscription requirements.

The test properly sets up the room with rawMessageReactions: true option, which is required for the subscribeRaw method to work without triggering the fatalError added in the implementation.


332-408: Comprehensive coverage of default reaction type configuration.

Both tests effectively validate the default reaction type behavior - custom configuration with .multiple and the default .distinct type. This ensures the refactored options-based approach works correctly.

Comment thread Tests/AblyChatTests/DefaultMessageReactionsTests.swift Outdated
@maratal maratal force-pushed the 304-message-reactions-tests branch from e737a23 to 8558e46 Compare July 19, 2025 13:37
@github-actions github-actions Bot temporarily deployed to staging/pull/332/AblyChat July 19, 2025 13:38 Inactive
@maratal maratal force-pushed the 304-message-reactions-tests branch from 8558e46 to 8765aad Compare July 19, 2025 15:41
@github-actions github-actions Bot temporarily deployed to staging/pull/332/AblyChat July 19, 2025 15:42 Inactive
@maratal maratal force-pushed the 301-all-errors-via-ChatError branch from 2065a8a to a87908c Compare July 19, 2025 16:26
@maratal maratal force-pushed the 304-message-reactions-tests branch from 8765aad to 079a904 Compare July 19, 2025 16:32
@github-actions github-actions Bot temporarily deployed to staging/pull/332/AblyChat July 19, 2025 16:34 Inactive
@maratal maratal force-pushed the 301-all-errors-via-ChatError branch from a87908c to 42874c6 Compare July 22, 2025 23:26
Base automatically changed from 301-all-errors-via-ChatError to main July 23, 2025 11:24
@maratal maratal force-pushed the 304-message-reactions-tests branch from 079a904 to 3f590f8 Compare July 24, 2025 14:11
@github-actions github-actions Bot temporarily deployed to staging/pull/332/AblyChat July 24, 2025 14:12 Inactive
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🔭 Outside diff range comments (2)
Sources/BuildTool/BuildTool.swift (2)

304-313: Regex still too rigid; allow intra-token whitespace and trim captured ID to fix missed spec points (e.g., CHA-MR3b, CHA-MR7b).

Your change allows indentation before “*”, but the pattern still assumes a single literal space between tokens and doesn’t trim the captured ID. If the spec has variable whitespace (e.g., “**@( CHA-MR3b )@” or multiple spaces), the ID will be captured with spaces and won’t match test tags, leading to “conformance to nonexistent spec points.”

Adjust the regex to tolerate whitespace around tokens and trim the ID:

-                let specPointLineRegex = /^\s*\*+ @\((.*?)\)@( @\[Testable\]@ )?/
+                // Tolerate whitespace between list marker, ID tokens, and Testable marker
+                let specPointLineRegex = /^\s*\*+\s*@\(\s*(.*?)\s*\)@\s*( @\[\s*Testable\s*\]@\s*)?/
@@
-                id = String(match.output.1)
+                // Trim any whitespace the spec may include inside @( ... )@
+                id = String(match.output.1).trimmingCharacters(in: .whitespacesAndNewlines)
                 isTestable = match.output.2 != nil

I can add a unit test for SpecPoint parsing that covers these whitespace variations if useful.


363-401: Conformance tag regex: handle // vs ///, no-indent lines, multi-digit OneOf counts, and stricter ID capture.

Current pattern requires indentation before “//”, supports only single-digit m/n for @specOneOf, and may be too permissive around ID spacing. This can cause legitimate tags to be missed.

Make the matcher more permissive and precise without changing capture indices used below:

-            let conformanceTagSourceLineRegex = /^\s+\/\/ @spec(OneOf|Partial|Untested|NotApplicable)?(?:\((\d)?\/(\d)?\))? (.*?)(?: - (.*))?$/
+            // - Allow 0+ indent and // or /// (doc comments)
+            // - Support multi-digit OneOf counts
+            // - Require at least one space before the ID, and trim-able capture for ID/comments
+            let conformanceTagSourceLineRegex = /^\s*\/\/+ @spec(OneOf|Partial|Untested|NotApplicable)?(?:\((\d+)\/(\d+)\))?\s+([A-Za-z0-9-]+)(?:\s*-\s*(.*))?$/

This keeps:

  • match.output.1 → type (“OneOf”, “Partial”, etc.)
  • match.output.2 → index (now multi-digit)
  • match.output.3 → total (now multi-digit)
  • match.output.4 → specPointID
  • match.output.5 → optional comment

If any tags rely on characters beyond [A-Za-z0-9-] in IDs, widen that character class accordingly, but this should match current CHA-* IDs.

If needed, I can scan the test sources to confirm if any tags use /// or 0 indent and adjust accordingly.

🧹 Nitpick comments (3)
Sources/BuildTool/BuildTool.swift (3)

456-462: Add quick debug output when spec-point IDs are invalid.

When throwing conformanceToNonexistentSpecPoints, logging the commit SHA and a small sample of matched spec IDs helps diagnosis.

I can submit a small follow-up adding a debug flag to print e.g. first 10 parsed IDs and the offending IDs to stderr before throwing.


580-593: Guard against division by zero in coverage percentage.

If there are zero testable points (edge case), double division will be invalid.

-                        percentageFormatter.string(from: NSNumber(value: Double(specPointCount) / Double(summary.testableSpecPointCount)))!,
+                        summary.testableSpecPointCount > 0
+                        ? percentageFormatter.string(from: NSNumber(value: Double(specPointCount) / Double(summary.testableSpecPointCount)))!
+                        : "n/a",

653-675: Optional: echo the spec commit SHA in the coverage report output.

Helps correlate CI logs with the exact spec version used.

Append a line like “Spec commit: ” to the printed summary.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3f590f8 and 67073d7.

📒 Files selected for processing (1)
  • Sources/BuildTool/BuildTool.swift (1 hunks)
🔇 Additional comments (1)
Sources/BuildTool/BuildTool.swift (1)

299-314: Spec point regex covers all CHA-MR lines in the live spec*

The verification script confirmed that the proposed specPointLineRegex matches every CHA-MR* ID (including CHA-MR3b, 3b2, 3b3, 6a, 6a3, 7b, 7b1, 7b3) in the current chat-features.textile. No changes are needed.

@maratal maratal merged commit e26a2cc into main Aug 15, 2025
41 checks passed
@maratal maratal deleted the 304-message-reactions-tests branch August 15, 2025 20:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Tests for message reactions

2 participants